package com.paw.qrcode.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpQrcodeService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lvzihai
 * @date 2022/6/23
 **/
@Slf4j
@RestController
public class WxController {

  @Autowired
  private WxMpService wxMpService;

  @Autowired
  WxMpMessageRouter wxMpMessageRouter;



  @RequestMapping("/wx/getAccessToken")
  public String getAccessToken() throws WxErrorException {

    String accessToken = wxMpService.getAccessToken();
    System.out.println("accessToken: "+accessToken);

    return accessToken;
  }


  @RequestMapping("/wx/getQrCodeUrl")
  public String getQrCodeUrl() throws WxErrorException {

    String sceneId = IdUtil.fastSimpleUUID();
    WxMpQrcodeService qrcodeService = wxMpService.getQrcodeService();
    WxMpQrCodeTicket wxMpQrCodeTicket = qrcodeService.qrCodeCreateTmpTicket(sceneId, 36000);
    String qrCodePictureUrl = qrcodeService.qrCodePictureUrl(wxMpQrCodeTicket.getTicket());

    System.out.println("qrCodePictureUrl: "+qrCodePictureUrl);

    return qrCodePictureUrl;
  }

  /**
   * 开发者通过检验 signature 对请求进行校验。若确认此次 GET 请求来自微信服务器，请原样返回 echostr 参数内容，则接入生效，成为开发者成功，否则接入失败。
   * 加密/校验流程如下：
   * 1）将token、timestamp、nonce三个参数进行字典序排序
   * 2）将三个参数字符串拼接成一个字符串进行sha1加密
   * 3）开发者获得加密后的字符串可与 signature 对比，标识该请求来源于微信
   * @param signature
   * @param timestamp
   * @param nonce
   * @param echostr
   * @return
   */
  @GetMapping("/wx/callback")
  public String checkSign(@RequestParam("signature") String signature,
      @RequestParam("timestamp") String timestamp,
      @RequestParam("nonce") String nonce,
      @RequestParam("echostr") String echostr) {
    boolean checkSignature = wxMpService.checkSignature(timestamp, nonce, signature);
    String result = checkSignature? echostr: "fail";
    return result;
  }

  @PostMapping("/wx/callback")
  public String wxCallback(@RequestBody String requestBody,
      @RequestParam(value = "signature",required = false) String signature,
      @RequestParam(value = "timestamp",required = false) String timestamp,
      @RequestParam(value = "nonce",required = false) String nonce,
      @RequestParam(value = "openid",required = false) String openid,
      @RequestParam(name = "encrypt_type", required = false) String encType,
      @RequestParam(name = "msg_signature", required = false) String msgSignature) {
    log.info("n接收微信请求：[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
            + " timestamp=[{}], nonce=[{}], requestBody=[n{}n] ",
        openid, signature, encType, msgSignature, timestamp, nonce, requestBody);

    if (StrUtil.isNotEmpty(signature) && !wxMpService.checkSignature(timestamp, nonce, signature)) {
      throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
    }

    String out = null;
    if (encType == null) {
      // 明文传输的消息
      WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
      WxMpXmlOutMessage outMessage = this.wxMpMessageRouter.route(inMessage);
      if (outMessage == null) {
        return "";
      }
      out = outMessage.toXml();
    } else if ("aes".equalsIgnoreCase(encType)) {
      // aes加密的消息
      WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(),
          timestamp, nonce, msgSignature);
      log.info("n消息解密后内容为：n[{}] ", inMessage.toString());
      WxMpXmlOutMessage outMessage = this.wxMpMessageRouter.route(inMessage);
      if (outMessage == null) {
        return "";
      }
      out = outMessage.toEncryptedXml(wxMpService.getWxMpConfigStorage());
    }
    log.info("n组装回复信息：[{}]", out);

    return out;
  }

}
